{#include main fluid=true}
  
  {#script}
  // Bean dependency graph built with d3.js
  // Based on https://observablehq.com/@d3/mobile-patent-suits 
  
  const nodes = [
  {#each info:devBeanInfos.getDependencyGraph(currentRequest.getParam('beanId')).nodes}
    { id:"{it.id}", kind:"{it.kind}", description:"{#if info:devBeanInfos.beanDescription ne "simple"}{it.description}{#else}{it.simpleDescription}{/if}", root:{#if it.id == currentRequest.getParam('beanId')}true{#else}false{/if} },
  {/each}
  ];
  const links = [
  {#each info:devBeanInfos.getDependencyGraph(currentRequest.getParam('beanId')).links}
    { source:"{it.source}", target:"{it.target}", type:"{it.type}" },
  {/each}
  ];
  
  const beanId = "{currentRequest.getParam('beanId')}";
  const chartContainer = document.getElementById('beanDepGraph_container');

  {|
  const types = ['directDependency','directDependent','dependency','lookup','producer'];
  const width = chartContainer.clientWidth;
  const height = chartContainer.clientHeight;
  const color = d3.scaleOrdinal(types, d3.schemeCategory10);
  
  // Legend colors
  const legendDirectDependency = document.querySelector(".legend-direct-dependency");
  legendDirectDependency.style.color = color('directDependency');
  const legendDirectDependent = document.querySelector(".legend-direct-dependent");
  legendDirectDependent.style.color = color('directDependent');
  const legendDependency = document.querySelector(".legend-dependency");
  legendDependency.style.color = color('dependency');
  const legendLookup = document.querySelector(".legend-lookup");
  legendLookup.style.color = color('lookup');
  const legendProducer = document.querySelector(".legend-producer");
  legendProducer.style.color = color('producer');
  
  function linkArc(d) {
    const r = Math.hypot(d.target.x - d.source.x, d.target.y - d.source.y);
    return `
        M${d.source.x},${d.source.y}
        A${r},${r} 0 0,1 ${d.target.x},${d.target.y}
        `;
  }
  
  const simulation = d3.forceSimulation(nodes)
      .force("link", d3.forceLink(links).id(d => d.id).distance(function(d) {
        return d.source.id === beanId || d.target.id === beanId ? 150 : 75;
      }))
      .force("charge", d3.forceManyBody().strength(-400))
      .force("center", d3.forceCenter(width / 3, height / 2))   
      .force("x", d3.forceX())
      .force("y", d3.forceY());
      
  function dragstart(event, d){
    // this line is needed, otherwise the simulation stops after few seconds
    if (!event.active) simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
  };
  
  function dragged(event, d) {
    d.fx = event.x;
    d.fy = event.y;
  }
  
  function dragended(event, d) {
    d.fx = event.x;
    d.fy = event.y;
  }
  
  let onZoom = function (e) {
    d3.select('svg g').attr('transform', e.transform);
  }
  
  const d3Zoom = d3.zoom()
        .scaleExtent([0, 1])
        .on("zoom", onZoom);
  
  const svg = d3.select("#beanDepGraph_area")
        .attr("preserveAspectRatio", "xMinYMin meet")
        .attr("viewBox", [0, 0, width, height])
        .style("font", "1rem sans-serif")
        .call(d3Zoom)
        .append("g");
        
   d3.select("#zoom_in").on("click", function() {
      d3Zoom.scaleBy(svg.transition().duration(750), 1.2);
    });
   d3.select("#zoom_out").on("click", function() {
      d3Zoom.scaleBy(svg.transition().duration(750), 0.8);
    });

  svg.append("defs").selectAll("marker")
    .data(types)
    .join("marker")
      .attr("id", d => `arrow-${d}`)
      .attr("viewBox", "0 -5 10 10")
      .attr("refX", 15)
      .attr("refY", -0.5)
      .attr("markerWidth", 6)
      .attr("markerHeight", 6)
      .attr("orient", "auto")
      .append("path")
      .attr("fill", color)
      .attr("d", "M0,-5L10,0L0,5");
      
  const link = svg.append("g")
      .attr("fill", "none")
      .attr("stroke-width", 1.5)
      .selectAll("path")
      .data(links)
      .join("path")
      .attr("stroke", d => color(d.type))
      .attr("marker-end", d => `url(${new URL(`#arrow-${d.type}`, location)})`);

  const node = svg.append("g")
      .attr("fill", "currentColor")
      .attr("stroke-linecap", "round")
      .attr("stroke-linejoin", "round")
      .selectAll("g")
      .data(nodes)
      .join("g")
      .call(d3.drag().on("drag", dragged).on("end", dragended).on("start", dragstart));

  node.append("circle")
      .attr("stroke", "white")
      .attr("stroke-width", 1)
      .attr("r", 5)
      .style("fill", d => d.root ? "red" : "black");

  node.append("a")
       .attr("xlink:href", d => "beanDependencyGraph?beanId=" + d.id)
       .append("svg:text")
       .attr("x", 8)
       .attr("y", "0.31em")
       .style("fill", "#1f77b4")
       .text(d => d.description);

  simulation.on("tick", () => {
    link.attr("d", linkArc);
    node.attr("transform", d => `translate(${d.x},${d.y})`);
  });

  |}
  {/script}
  {#style}
    #beanDepGraph_container {
      min-height: 800px;
    }
  {/style}
  {#breadcrumbs}<i class="fas fa-chevron-right fa-sm breadcrumb-separator"></i> <a href="beans">Beans</a>{/breadcrumbs}
  {#title}Bean Dependency Graph{/title}
  {#body}
  {#let bean=info:devBeanInfos.getBean(currentRequest.getParam('beanId'))}
  
  
    <div class="row">
        <div class="col text-center">
            <span class="text-secondary h4">{bean.description}</span>
        </div>
    </div>
    <div class="row">
        <div class="col-2">
            <ul class="list-group list-group-flush">
                <li class="list-group-item"><i class="fas fa-circle text-danger fa-sm legend-root"></i> root</li>
                <li class="list-group-item"><i class="fa fa-long-arrow-right fa-sm legend-direct-dependency"></i> direct dependencies</li>
                <li class="list-group-item"><i class="fa fa-long-arrow-right fa-sm legend-direct-dependent"></i> direct dependents</li>
                <li class="list-group-item"><i class="fa fa-long-arrow-right fa-sm legend-dependency"></i> dependencies</li>
                <li class="list-group-item"><i class="fa fa-long-arrow-right fa-sm legend-producer"></i> declaring bean of a producer</li>
                <li class="list-group-item"><i class="fa fa-long-arrow-right fa-sm legend-lookup"></i> potential dependency <br/> &nbsp;<small class="text-muted">programmatic lookup</small></li>
                <li class="list-group-item">
                    <div class="btn-group" role="group" aria-label="Zoom">
                        <button class="btn btn-outline-secondary" type="button" id="zoom_in">
                            Zoom in <i class="fas fa-search-plus"></i>
                        </button>
                        <button class="btn btn-outline-secondary" type="button" id="zoom_out">
                            <i class="fas fa-search-minus"></i> Zoom out
                        </button>
                    </div>
                </li>
                <li class="list-group-item">
                <form id="simpleDescriptionForm" method="post" action="toggleBeanDescription?beanId={bean.id}">
                    <div class="form-check">
                        <input type="checkbox" class="form-check-input" id="simpleDescriptionCheck" title="Simple description does not include the package information" onclick="this.form.submit();" {#if info:devBeanInfos.beanDescription eq "simple"}checked{/if}>
                        <label class="form-check-label" for="simpleDescriptionCheck">Simple description</label>
                    </div>
                </form>
                </li>
                <li class="list-group-item">
                <form method="post" action="setMaxDependencyLevel?beanId={bean.id}">
                    <label for="maxDepLevel">Max dependency level:</label>
                    <input type="number" value="{info:devBeanInfos.maxDependencyLevel}" class="form-control" id="maxDepLevel" name="maxDepLevel" min="0" max="1000" onchange="this.form.submit();">
                    <small class="form-text text-muted">Value <code>0</code> means only direct dependencies</small>
                </form>
                </li>
            </ul>
        </div>
        <div class="col-10">
            <div id="beanDepGraph_container" class="w-100">
                <svg id="beanDepGraph_area"></svg>
            </div>
        </div>
    </div>
  
  {/let}
  {/body}
  
  {#scriptref}
  <script src="{devRootAppend}/resources/js/d3.min.js"></script>
  {/scriptref}
{/include}
